package com.michaelbulava.TFS.actions;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsUtil;
import com.michaelbulava.TFS.Messages;
import com.michaelbulava.TFS.tasks.BackgroundableTask;
import com.michaelbulava.TFS.vcs.exceptions.TFSException;
import com.michaelbulava.TFS.vcs.internal.SharedOperations;
import com.michaelbulava.TFS.vcs.internal.WorkstationHelper;
import com.michaelbulava.TFS.vcs.utils.TFSFileUtil;
import com.michaelbulava.TFS.vcs.utils.TFSProgressUtil;
import com.microsoft.tfs.core.clients.versioncontrol.GetItemsOptions;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.*;
import com.microsoft.tfs.core.clients.versioncontrol.specs.ItemSpec;
import com.microsoft.tfs.util.Check;

import java.util.*;

/**
 * Created by MichaelA on 8/31/2015.
 */
public class DetectLocalChangesAction extends OnlineRequiredAction {

    /**
     * Implement this method to provide your action handler.
     *
     * @param e Carries information on the invocation place
     */
    @Override
    public void actionPerformed(AnActionEvent e) {
        Project project = (Project)e.getData(CommonDataKeys.PROJECT);
        VirtualFile[] files = VcsUtil.getVirtualFiles(e);
        DetectLocalChangesTask task = new DetectLocalChangesTask(project, files);
        ProgressManager.getInstance().run(task);
    }

    public static class DetectLocalChangesTask extends BackgroundableTask{
        private final VirtualFile[] selectedFiles;
        private final ChangeListManager changeListManager;

        protected DetectLocalChangesTask(Project project, VirtualFile[] virtualFiles) {
            super(project, Messages.getString("DetectLocalChangesAction.DetectLocalChangesTask.Title"), true);
            selectedFiles = virtualFiles;
            changeListManager = ChangeListManager.getInstance(this.myProject);
        }

        @Override
        protected boolean runInBackground() {
            return false;
        }

        @Override
        public void run(final ProgressIndicator indicator) {
            TFSProgressUtil.setProgressText(indicator, "Detecting local changes..");
            List<FilePath> fpRoots = new ArrayList<>();

            for(VirtualFile file : selectedFiles){
                FilePath filePath = TFSFileUtil.getFilePath(file);
                if(filePath.isDirectory()){
                    fpRoots.addAll(TFSFileUtil.getFilePaths(TFSFileUtil.recursivelyGetFilesAndFolders(myProject, file)));
                } else {
                    if (!fpRoots.contains(filePath))
                        fpRoots.add(filePath);
                }
            }

            try {
                WorkstationHelper.processByWorkspaces(fpRoots, true, myProject, indicator, new WorkstationHelper.VoidDelegateProcess() {
                    @Override
                    public void executeRequest(Workspace workspace, List<FilePath> localPaths) throws TFSException {

                        List<FilePath> added = new ArrayList<FilePath>();
                        List<FilePath> edited = new ArrayList<FilePath>();
                        List<FilePath> deleted = new ArrayList<FilePath>();

                        PendingChange[] pendingChanges = workspace.getPendingChanges().getPendingChanges();
                        ItemSpec[] itemSpecs = TFSFileUtil.getItemSpecs(myProject, workspace, localPaths, true, false);
                        ExtendedItem[][] extendedItems = workspace.getExtendedItems(itemSpecs, DeletedState.ANY, ItemType.ANY);

                        Map<FilePath, ExtendedItem> filePathExtendedItemMap =TFSFileUtil.getFileExtendedItems(myProject,
                                workspace, localPaths, DeletedState.ANY,
                                GetItemsOptions.NONE, true);

                        Map<FilePath, PendingChange> filePathPendingChangeMap = new HashMap<FilePath, PendingChange>();
                        for(int i = 0; i < pendingChanges.length; i++){
                            FilePath file = TFSFileUtil.getFilePath(pendingChanges[i].getLocalItem(),
                                    pendingChanges[i].getItemType() == ItemType.FOLDER);
                            filePathPendingChangeMap.put(file, pendingChanges[i]);
                        }

                        //figure out what's changed now...
                        for(Map.Entry<FilePath, ExtendedItem> entry : filePathExtendedItemMap.entrySet()){
                            FilePath localFile = entry.getKey();
                            if (localFile.getIOFile().exists()){

                                if (TFSFileUtil.isFileWritable(localFile)){
                                    PendingChange filePendingChange = filePathPendingChangeMap.get(localFile);
                                    if (filePendingChange == null ||
                                            filePendingChange.getChangeType() != ChangeType.NONE ){

                                        if (entry.getValue() == null)
                                            added.add(localFile);
                                        else
                                            edited.add(localFile);
                                    }
                                }
                                //If file isn't writable (readonly) we can assume it hasn't changed.
                            } else {
                                //looks like the file was deleted
                                deleted.add(localFile);
                            }
                        }

                        if (!added.isEmpty())
                            SharedOperations.scheduleForAddition(myProject, workspace, added);
                        if (!edited.isEmpty())
                            SharedOperations.performCheckout(myProject, workspace, edited);
                        if (!deleted.isEmpty())
                            SharedOperations.scheduleForDeletion(myProject, workspace, deleted, indicator);
                    }
                });
            } catch (TFSException e) {
                e.printStackTrace();
            }
        }

        private FileStatus detectFolderChangesRecursively(VirtualFile folder){
            Check.isTrue(folder.isDirectory(), "folder must be a Directory");
            VirtualFile[] children = folder.getChildren();
            FileStatus CurrentFolderStatus = changeListManager.getStatus(folder);
            FileStatus NewFolderStatus = null;
            for(VirtualFile child : children){
                if (child.isDirectory())
                    NewFolderStatus = detectFolderChangesRecursively(child);
                else {
                    FileStatus fileStatus = processFileChange(child);
                    //TODO need to look at the file status and determine if the folder status needs to be updated.
                }
            }
            if (NewFolderStatus != null && !CurrentFolderStatus.equals(NewFolderStatus)){
                //TODO update the folder's status
            }
            return NewFolderStatus;
        }

        private FileStatus processFileChange(VirtualFile file){
            Check.isTrue(!file.isDirectory(), "file must not be a Directory");

            return FileStatus.NOT_CHANGED;
        }
    }
}
